package com.supreme.aspectserver.aspect;

import com.supreme.aspectserver.annotation.RecorderAnno;
import com.supreme.aspectserver.service.recorder.RecordData;
import com.supreme.aspectserver.service.recorder.Recorder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Consumer;

@Slf4j
@Aspect
@Component
public class RecorderAOP {

    private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)
    );

    @Pointcut(value = "@annotation(com.supreme.aspectserver.annotation.RecorderAnno)")
    public void PointCut() {
    }

    @Before("PointCut()")
    public void doBefore(JoinPoint joinPoint) {
        threadPoolExecutor.execute(() -> {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            RecorderAnno recorderAnno = method.getAnnotation(RecorderAnno.class);
            if (Objects.nonNull(recorderAnno)) {
                Class<? extends Recorder> recorder = recorderAnno.recorder();
                try {
                    Recorder logRecorder = recorder.newInstance();
                    Object[] args = joinPoint.getArgs();
                    List<Object> argList = Arrays.asList(args);
                    RecordData recordData = logRecorder.record(argList);
                    String desc = recorderAnno.desc();
                    if (Objects.nonNull(recordData) && StringUtils.isNotBlank(desc)) {
                        Class<? extends RecordData> recordDataClass = recordData.getClass();
                        Field descField = recordDataClass.getDeclaredField("desc");
                        descField.setAccessible(true);
                        descField.set(recordData, desc);

                        String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        recordData.setDate(format);

                        System.out.println("recordData = " + recordData);
                    }
                } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    @AfterReturning(pointcut = "PointCut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {

    }
}
